package com.kepler.social.app.cases;

import com.kepler.social.app.converter.UserMoodCaseConverter;
import com.kepler.social.app.port.UserMoodPort;
import com.kepler.social.app.port.UserMoodToMediaPort;
import com.kepler.social.common.Wrapper;
import com.kepler.social.common.constants.BusinessState;
import com.kepler.social.common.constants.PostType;
import com.kepler.social.common.constants.RedisKeyConst;
import com.kepler.social.common.utils.Safes;
import com.kepler.social.domain.port.vo.CreateMoodCaseVo;
import com.kepler.social.domain.port.vo.ResultVo;
import com.kepler.social.domain.support.media.MediaDomainService;
import com.kepler.social.domain.support.media.consts.CallBackType;
import com.kepler.social.domain.support.media.vo.CallBackVo;
import com.kepler.social.domain.support.media.vo.FileSliceMergeRsVo;
import com.kepler.social.domain.user.mood.UserMoodDomainService;
import com.kepler.social.domain.user.mood.vo.CreateMoodVo;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


/**
 *
 */

@Service
@Slf4j
public class UserMoodCase implements UserMoodPort, UserMoodToMediaPort {

    @Resource
    private MediaDomainService mediaDomainService;
    @Resource
    private UserMoodDomainService userMoodDomainService;
    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public void createMood(CreateMoodCaseVo caseVo) {
        String seqNo = caseVo.getSeqNo();
        PostType postType = PostType.getByType(caseVo.getPostType());
        CreateMoodVo vo = UserMoodCaseConverter.createMoodVo(caseVo);
        Long moodId;
        assert Objects.nonNull(postType);
        switch (postType) {
            case text:
                // 文本直接返回成功
                moodId = userMoodDomainService.createTextMood(vo);
                break;
            case text_image:
            case text_video:
                //先持久化
                moodId = userMoodDomainService.preCreateMediaMood(vo);
                //设置标志
                this.setMergeTaskProcessState(seqNo,new ResultVo());
                //提交合并分片任务并且设置回调操作
                mediaDomainService.submitMergeSliceTask(
                        caseVo.getFileSlices(),
                        CallBackVo.builder()
                                // seqNo + "_" + moodId
                                // 如果不合在一起，那就需要再搞一个映射，seqNo -> moodId，没这必要
                                .businessKey(seqNo + "_" + moodId)
                                .callBackType(CallBackType.spring_ioc)
                                .className("userMoodCase")
                                .classMethodName("slicesMergeCallBack")
                                .build()
                );
                break;
            default:
                throw new IllegalArgumentException("参数错误");
        }
    }

    @Override
    public void slicesMergeCallBack(String businessKey, Wrapper<List<FileSliceMergeRsVo>> resultWrapper) {
        String[] keys = businessKey.split("_");
        // businessKey是回调透传过来的，不应出问题，所以直接assert
        assert keys.length == 2;
        assert StringUtils.isNoneBlank(keys[0]);
        assert StringUtils.isNumeric(keys[1]);
        this.finishCreateMood(keys[0], Long.parseLong(keys[1]), resultWrapper.getCore());
    }

    @Override
    public void finishCreateMood(String seqNo, Long moodId, List<FileSliceMergeRsVo> mergeRss) {
        FileSliceMergeRsVo failureMerge = Safes.of(mergeRss).stream().filter(e -> !e.isSuccess()).findFirst().orElse(null);
        if(Objects.nonNull(failureMerge)){
            log.error("slicesMergeCallBack  reqSeq {} message {}", failureMerge.getSeqNo(), failureMerge.getMessage());
            // todo 删除mood

            // 设置标志为失败
            this.setMergeTaskProcessState(seqNo, new ResultVo(BusinessState.BUSINESS_ERROR.code, failureMerge.getMessage()));
            return;
        }
        // todo 将数据持久化到数据库
        // 头都 设置标志变量为成功
        this.setMergeTaskProcessState(seqNo, new ResultVo(BusinessState.OK.code, null));
    }

    @Override
    public ResultVo querySliceMergeResult(String seqNo) {
        return this.getMergeTaskProcessState(seqNo);
    }

    /**
     * 设置处理标志
     *
     * @param seqNo
     * @param value
     */
    private void setMergeTaskProcessState(String seqNo, ResultVo value) {
        // 之所以设置两小时，是因为用户不可能在提交页面等待这么长的时间，前端可以灵活控制，比如超过多长时间就提示用户稍后刷新等等
        redisTemplate.opsForValue().set(RedisKeyConst.MEDIA_SLICE_MERGE_TASK_PROCESS_STATE_PREFIX + seqNo,
                value, 2, TimeUnit.HOURS);
    }

    /**
     * 返回处理标志
     *
     * @param seqNo
     * @return
     */
    private ResultVo getMergeTaskProcessState(String seqNo) {
        return (ResultVo) redisTemplate.opsForValue().get(RedisKeyConst.MEDIA_SLICE_MERGE_TASK_PROCESS_STATE_PREFIX + seqNo);
    }
}
